package k8s

import (
	snapshotclient "github.com/kubernetes-csi/external-snapshotter/v2/pkg/client/clientset/versioned"
	"github.com/spf13/pflag"
	apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
	"k8s.io/client-go/discovery"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
	"kubeconsole/client/api"
	"os"
)

type KubernetesOptions struct {
	KubeConfig string `json:"kubeconfig" yaml:"kubeconfig"`

	Master string `json:"master,omitempty" yaml:"master"`

	QPS float32 `json:"qps,omitemtpy" yaml:"qps"`

	Burst int `json:"burst,omitempty" yaml:"burst"`
}

func NewKubernetesOptions() *KubernetesOptions {
	return &KubernetesOptions{
		KubeConfig: "",
		QPS:        1e6,
		Burst:      1e6,
	}
}
func NewKubernetesOptionsWithConfig(kubeconfig, master string) *KubernetesOptions {
	return &KubernetesOptions{
		KubeConfig: kubeconfig,
		Master:     master,
		QPS:        1e6,
		Burst:      1e6,
	}
}

func (k *KubernetesOptions) Validate() []error {
	errors := []error{}

	if k.KubeConfig != "" {
		if _, err := os.Stat(k.KubeConfig); err != nil {
			errors = append(errors, err)
		}
	}
	return errors
}

func (k *KubernetesOptions) AddFlags(fs *pflag.FlagSet, c *KubernetesOptions) {
	fs.StringVar(&k.KubeConfig, "kubeconfig", c.KubeConfig, ""+
		"Path for kubernetes kubeconfig file, if left blank, will use "+
		"in cluster way.")

	fs.StringVar(&k.Master, "master", c.Master, ""+
		"Used to generate kubeconfig for downloading, if not specified, will use host in kubeconfig.")
}

type K8sClient struct {
	// kubernetes client interface
	k8s kubernetes.Interface
	// discovery client
	discoveryClient *discovery.DiscoveryClient

	apiextensions apiextensionsclient.Interface

	snapshot snapshotclient.Interface

	master string

	config *rest.Config
}

func (k *K8sClient) Kubernetes() kubernetes.Interface {
	return k.k8s
}

func (k *K8sClient) Discovery() discovery.DiscoveryInterface {
	return k.discoveryClient
}

func (k *K8sClient) ApiExtensions() apiextensionsclient.Interface {
	return k.apiextensions
}
func (k *K8sClient) Snapshot() snapshotclient.Interface {
	return k.snapshot
}

// master address used to generate kubeconfig for downloading
func (k *K8sClient) Master() string {
	return k.master
}

func (k *K8sClient) Config() *rest.Config {
	return k.config
}

func NewKubernetesClient(options *KubernetesOptions) (api.K8sClientInterface, error) {

	var config *rest.Config
	var err error

	if options.KubeConfig == "" {
		config, err = rest.InClusterConfig()
		if err != nil {
			return nil, err
		}
	} else {
		config, err = clientcmd.BuildConfigFromFlags("", options.KubeConfig)
		if err != nil {
			return nil, err
		}
	}

	config.QPS = options.QPS
	config.Burst = options.Burst

	var k K8sClient
	k.k8s, err = kubernetes.NewForConfig(config)
	if err != nil {
		return nil, err
	}

	k.apiextensions, err = apiextensionsclient.NewForConfig(config)
	if err != nil {
		return nil, err
	}

	k.snapshot, err = snapshotclient.NewForConfig(config)
	if err != nil {
		return nil, err
	}

	k.master = options.Master
	k.config = config

	return &k, nil
}
